diff options
| author | joonhoekim <26rote@gmail.com> | 2025-08-27 08:24:58 +0000 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-08-27 08:24:58 +0000 |
| commit | e2ed31dd0112dc3bede53ceef9b957d2810e141e (patch) | |
| tree | 9727511febf5b51ee897b0ae2f24f6b68a95cbad /app/[lng]/admin/edp/components/contract-items-edit-form.tsx | |
| parent | 026ce088c638b50f493fe9aedf36e0659cb368c3 (diff) | |
(김준회) 임시 관리자 페이지 - EDP 데이터 수동 관리 추가 및 세션검증 추가
Diffstat (limited to 'app/[lng]/admin/edp/components/contract-items-edit-form.tsx')
| -rw-r--r-- | app/[lng]/admin/edp/components/contract-items-edit-form.tsx | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/app/[lng]/admin/edp/components/contract-items-edit-form.tsx b/app/[lng]/admin/edp/components/contract-items-edit-form.tsx new file mode 100644 index 00000000..18fe75de --- /dev/null +++ b/app/[lng]/admin/edp/components/contract-items-edit-form.tsx @@ -0,0 +1,204 @@ +'use client' + +import { useState, useEffect } from 'react' +import { Button } from '@/components/ui/button' + +import { Label } from '@/components/ui/label' +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' +import { Badge } from '@/components/ui/badge' +import { toast } from 'sonner' +import { deleteContractItem } from '../actions/contract-actions' +import { getContractItems } from '../actions/data-actions' +import { ContractSelector } from './contract-selector' +import { Trash2 } from 'lucide-react' + +interface Contract { + id: number + contractNo: string + contractName: string + status: string + projectId: number + vendorId: number + projectCode: string | null + projectName: string | null + vendorName: string | null + vendorCode: string | null +} + +interface ContractItem { + id: number + contractId: number + itemId: number + description: string | null + quantity: number + unitPrice: number | null + ProjectNo: string | null + itemCode: string | null + itemName: string | null + packageCode: string | null + unitOfMeasure: string | null +} + +interface ContractItemsEditFormProps { + preselectedContractId?: number +} + +export function ContractItemsEditForm({ preselectedContractId }: ContractItemsEditFormProps) { + const [loading, setLoading] = useState(false) + const [selectedContract, setSelectedContract] = useState<Contract | undefined>() + const [contractItems, setContractItems] = useState<ContractItem[]>([]) + + // 계약 선택 시 아이템들 로드 + useEffect(() => { + if (selectedContract) { + loadContractItems(selectedContract.id) + } + }, [selectedContract]) + + const loadContractItems = async (contractId: number) => { + setLoading(true) + try { + const result = await getContractItems(contractId) + if (result.success) { + setContractItems(result.data) + } else { + toast.error(result.error) + } + } catch (error) { + toast.error('계약 아이템을 불러오는 중 오류가 발생했습니다.') + } finally { + setLoading(false) + } + } + + + + const handleDelete = async (itemId: number) => { + if (!confirm('정말로 이 계약 아이템을 삭제하시겠습니까?')) { + return + } + + setLoading(true) + try { + const result = await deleteContractItem(itemId) + + if (result.success) { + toast.success(result.message) + // 아이템 목록 새로고침 + if (selectedContract) { + await loadContractItems(selectedContract.id) + } + } else { + toast.error(result.error) + } + } catch (error) { + toast.error('계약 아이템 삭제 중 오류가 발생했습니다.') + } finally { + setLoading(false) + } + } + + return ( + <Card> + <CardHeader> + <CardTitle>계약 아이템 삭제</CardTitle> + <CardDescription> + 기존 계약의 아이템들을 삭제할 수 있습니다. + </CardDescription> + </CardHeader> + <CardContent> + <div className="space-y-6"> + {/* 계약 선택 */} + <div> + <Label>계약 선택 *</Label> + <ContractSelector + selectedContract={selectedContract} + onContractSelect={setSelectedContract} + disabled={loading} + preselectedContractId={preselectedContractId} + /> + </div> + + {selectedContract && ( + <div className="bg-muted/50 p-3 rounded-md"> + <div className="text-sm font-medium">선택된 계약</div> + <div className="text-sm text-muted-foreground"> + [{selectedContract.contractNo}] {selectedContract.contractName} + </div> + </div> + )} + + {/* 계약 아이템 목록 */} + {contractItems.length > 0 && ( + <div> + <Label>계약 아이템 목록 ({contractItems.length}개)</Label> + <div className="mt-2 space-y-3 max-h-96 overflow-y-auto border rounded-md p-3"> + {contractItems.map(item => ( + <div key={item.id} className="p-3 bg-white border rounded-md"> + <div className="flex items-start justify-between"> + <div className="flex-1"> + <div className="flex items-center gap-2 mb-2"> + <span className="font-medium">{item.itemName || `아이템 ${item.itemId}`}</span> + {item.itemCode && ( + <Badge variant="outline" className="text-xs"> + {item.itemCode} + </Badge> + )} + {item.unitOfMeasure && ( + <Badge variant="secondary" className="text-xs"> + {item.unitOfMeasure} + </Badge> + )} + </div> + + {item.ProjectNo && ( + <div className="text-xs text-muted-foreground mb-1"> + 프로젝트: {item.ProjectNo} | 패키지: {item.packageCode} + </div> + )} + + {/* 보기 모드만 유지 */} + <div className="text-sm space-y-1"> + <div>수량: {item.quantity} | 단가: {item.unitPrice || 0}</div> + {item.description && ( + <div className="text-muted-foreground">설명: {item.description}</div> + )} + </div> + </div> + + {/* 삭제 버튼만 유지 */} + <div className="flex gap-1 ml-2"> + <Button + type="button" + variant="ghost" + size="sm" + onClick={() => handleDelete(item.id)} + disabled={loading} + className="text-red-600 hover:text-red-700" + > + <Trash2 className="h-4 w-4" /> + </Button> + </div> + </div> + </div> + ))} + </div> + </div> + )} + + {selectedContract && contractItems.length === 0 && !loading && ( + <div className="text-center py-8 text-muted-foreground"> + 선택된 계약에 아이템이 없습니다. + </div> + )} + + {loading && ( + <div className="text-center py-8 text-muted-foreground"> + 로딩 중... + </div> + )} + </div> + </CardContent> + </Card> + ) +} |
